package org.openmrs.web.controller.user;

import java.io.ByteArrayInputStream;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.openmrs.Role;
import org.openmrs.User;
import org.openmrs.api.UserService;
import org.openmrs.api.context.Context;
import org.openmrs.util.PolicyGenerator;
import org.openmrs.util.UserInformation;
import org.springframework.beans.propertyeditors.CustomNumberEditor;
import org.springframework.validation.BindException;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import org.w3c.dom.Document;

public class PolicyMigrationListController extends SimpleFormController {
	
	protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
		super.initBinder(request, binder);
		binder.registerCustomEditor(java.lang.Integer.class, new CustomNumberEditor(java.lang.Integer.class, true));
	}
	
	protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object obj,
	        BindException errors) throws Exception {
		
		Object usersMapObject = request.getAttribute("usersMap");
		Object methodology = request.getParameter("method");
		
		String fileName = "openmrs-role-policy.xml";
		boolean isUserBased = false;
		
		if (usersMapObject != null) {
			
			if (methodology.equals("user")) {
				fileName = "openmrs-user-policy.xml";
				isUserBased = true;
			}
			
			Map<String, UserInformation> usersMap = (Map<String, UserInformation>) usersMapObject;
			PolicyGenerator policyGenerator = PolicyGenerator.getInstance();
			String policyContent = policyGenerator.getPolicyContent(usersMap, isUserBased);
			
			response.setContentType("text/xml");
			response.setCharacterEncoding("UTF-8");
			response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
			response.setHeader("Pragma", "public");
			response.setHeader("Cache-Control", "max-age=0");
			
			PrintWriter writer = response.getWriter();
			
			TransformerFactory transformerFactory = TransformerFactory.newInstance();
			Transformer transformer = transformerFactory.newTransformer();
			
			DocumentBuilderFactory docBuildFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = docBuildFactory.newDocumentBuilder();
			Document document = docBuilder.parse(new ByteArrayInputStream(policyContent.getBytes()));
			
			DOMSource domSource = new DOMSource(document);
			StreamResult streamResult = new StreamResult(writer);
			transformer.transform(domSource, streamResult);
		}
		
		return null;
	}
	
	protected Object formBackingObject(HttpServletRequest request) throws ServletException {
		Map<String, UserInformation> usersMap = new HashMap<String, UserInformation>();
		
		UserService userService = Context.getUserService();
		List<String> exceptedUsers = userService.getAuthExceptedUserList();
		
		List<User> userList = userService.getAllUsers();
		
		for (User user : userList) {
			if (user != null && !exceptedUsers.contains(user.getUsername())) {
				UserInformation userInfo = new UserInformation();
				
				Set<Role> roles = user.getAllRoles();
				
				for (Role role : roles) {
					userInfo.getAssignedRoles().add(role.getRole());
				}
				
				userInfo.setVirtualRole(userService.getVirtualRole(user));
				usersMap.put(user.getUsername(), userInfo);
			}
			
		}
		
		request.setAttribute("usersMap", usersMap);
		//only fill the Object is the user has authenticated properly
		return usersMap;
	}
}
